package com.xuecheng.content.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xuecheng.base.exception.CommonError;
import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.base.utils.FileUtil;
import com.xuecheng.content.config.MultipartSupportConfig;
import com.xuecheng.content.feignclient.MediaServiceClient;
import com.xuecheng.content.mapper.CourseBaseMapper;
import com.xuecheng.content.mapper.CourseMarketMapper;
import com.xuecheng.content.mapper.CoursePublishMapper;
import com.xuecheng.content.mapper.CoursePublishPreMapper;
import com.xuecheng.content.model.dto.CourseBaseInfoDto;
import com.xuecheng.content.model.dto.CoursePreviewDto;
import com.xuecheng.content.model.dto.CourseTeacherDto;
import com.xuecheng.content.model.dto.TeachplanDto;
import com.xuecheng.content.model.po.CourseBase;
import com.xuecheng.content.model.po.CourseMarket;
import com.xuecheng.content.model.po.CoursePublish;
import com.xuecheng.content.model.po.CoursePublishPre;
import com.xuecheng.content.service.CourseBaseInfoService;
import com.xuecheng.content.service.CoursePublishService;
import com.xuecheng.content.service.CourseTeacherService;
import com.xuecheng.content.service.TeachplanService;
import com.xuecheng.messagesdk.model.po.MqMessage;
import com.xuecheng.messagesdk.service.MqMessageService;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;

/**
 * @author shiminghui
 * @date 2024/9/1 16:03
 * @description: TODO
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CoursePublishServiceImpl implements CoursePublishService {

    private final CourseBaseInfoService courseBaseInfoService;
    private final TeachplanService teachplanService;
    private final CourseTeacherService courseTeacherService;
    private final CourseMarketMapper courseMarketMapper;
    private final CoursePublishPreMapper coursePublishPreMapper;
    private final CoursePublishMapper coursePublishMapper;
    private final CourseBaseMapper courseBaseMapper;
    private final MqMessageService mqMessageService;
    private final MediaServiceClient mediaServiceClient;
    private final StringRedisTemplate stringRedisTemplate;


    /**
     * 查询课程信息和课程计划
     *
     * @param courseId
     * @return
     */
    @Override
    public CoursePreviewDto getCoursePreviewInfo(Long courseId) {

        CoursePreviewDto coursePreviewDto = new CoursePreviewDto();

        //查询课程基本信息
        CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId);
        if (courseBaseInfo == null) {
            XueChengPlusException.cast("未查询到此课程");
        }
        coursePreviewDto.setCourseBase(courseBaseInfo);

        //查询课程计划
        List<TeachplanDto> teachplans = teachplanService.getTreeNodes(courseId);
//        if (teachplans==null||teachplans.size()==0){
//            XueChengPlusException.cast("未查询到课程计划");
//        }
        coursePreviewDto.setTeachplans(teachplans);

        return coursePreviewDto;
    }

    /**
     * 提交审核
     *
     * @param companyId 企业id
     * @param courseId  课程id
     */
    @Override
    @Transactional
    public void commitAudit(Long companyId, Long courseId) {

        //先查询课程基本信息数据
        CourseBaseInfoDto courseBaseInfo = courseBaseInfoService.getCourseBaseInfo(courseId);

        //课程审核状态
        String auditStatus = courseBaseInfo.getAuditStatus();
        //当前审核状态为已提交不允许再次提交
        if ("202003".equals(auditStatus)) {
            XueChengPlusException.cast("当前为等待审核状态，审核完成可以再次提交。");
        }
        //本机构只允许提交本机构的课程
        if (!courseBaseInfo.getCompanyId().equals(companyId)) {
            XueChengPlusException.cast("不允许提交其它机构的课程。");
        }

        //课程图片是否填写
        if (StringUtils.isEmpty(courseBaseInfo.getPic())) {
            XueChengPlusException.cast("提交失败，请上传课程图片");
        }


        CoursePublishPre coursePublishPre = new CoursePublishPre();
        BeanUtil.copyProperties(courseBaseInfo, coursePublishPre);

        //查询课程营销信息
        CourseMarket courseMarket = courseMarketMapper.selectById(courseId);
        String courseMarketJson = JSON.toJSONString(courseMarket);
        coursePublishPre.setMarket(courseMarketJson);

        //查询课程计划数据
        List<TeachplanDto> teachplanTree = teachplanService.getTreeNodes(courseId);

        //校验课程计划
        if (teachplanTree.size() <= 0) {
            XueChengPlusException.cast("提交失败，还没有添加课程计划");
        }

        String teachplanJson = JSON.toJSONString(teachplanTree);
        coursePublishPre.setTeachplan(teachplanJson);

        //查询师资信息表
        List<CourseTeacherDto> byCourseId = courseTeacherService.getByCourseId(courseId);
        String courseTeacherJson = JSON.toJSONString(byCourseId);
        coursePublishPre.setTeachers(courseTeacherJson);

        //设置课程状态
        coursePublishPre.setStatus("202003");
        //提交时间
        coursePublishPre.setCreateDate(LocalDateTime.now());

        //将数据保存到预发布表
        CoursePublishPre coursePublishPre1 = coursePublishPreMapper.selectById(courseId);
        if (coursePublishPre1 == null) {
            coursePublishPreMapper.insert(coursePublishPre);
        } else {
            coursePublishPreMapper.updateById(coursePublishPre);
        }

        //在修改课程信息表的课程状态
        CourseBase courseBase = new CourseBase();
        BeanUtil.copyProperties(courseBaseInfo, courseBase);
        courseBase.setAuditStatus("202003");
        courseBaseInfoService.updateById(courseBase);


    }

    /**
     * 发布课程
     *
     * @param companyId
     * @param courseId
     */
    @Override
    @Transactional
    public void publish(Long companyId, Long courseId) {
        //约束校验
        //查询课程预发布表
        CoursePublishPre coursePublishPre = coursePublishPreMapper.selectById(courseId);
        if (coursePublishPre == null) {
            XueChengPlusException.cast("请先提交课程审核，审核通过才可以发布");
        }
        //本机构只允许提交本机构的课程
        if (!coursePublishPre.getCompanyId().equals(companyId)) {
            XueChengPlusException.cast("不允许提交其它机构的课程。");
        }


        //课程审核状态
        String auditStatus = coursePublishPre.getStatus();
        //审核通过方可发布
        if (!"202004".equals(auditStatus)) {
            XueChengPlusException.cast("操作失败，课程审核通过方可发布。");
        }

        //保存课程发布信息
        saveCoursePublish(courseId);

        //保存消息表
        saveCoursePublishMessage(courseId);

        //删除课程预发布表对应记录
        coursePublishPreMapper.deleteById(courseId);
    }

    /**
     * 生成静态化页面
     *
     * @param courseId 课程id
     * @return
     */
    @Override
    public File generateCourseHtml(Long courseId) {
        Configuration configuration = new Configuration(Configuration.getVersion());

        //获取静态资源所在路径
        String classpath = this.getClass().getResource("/").getPath();

        //最终生成的静态文件
        File htmlFile = null;

        try {

            //设置模板的所在路径
            configuration.setDirectoryForTemplateLoading(new File(classpath + "/templates/"));

            //设置字符编码
            configuration.setDefaultEncoding("utf-8");


            //获得模板
            Template template = configuration.getTemplate("course_template.ftl");

            //获取数据
            CoursePreviewDto coursePreviewInfo = this.getCoursePreviewInfo(courseId);

            HashMap<String, Object> map = new HashMap<>();
            map.put("model", coursePreviewInfo);

            //静态化
            //参数1：模板，参数2：数据模型
            String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
            System.out.println(content);
            //将静态化内容输出到文件中
            InputStream inputStream = IOUtils.toInputStream(content, "utf-8");

            //生成临时文件
            htmlFile = File.createTempFile("course", ".html");

            //输出流
            FileOutputStream outputStream = new FileOutputStream(htmlFile);
            IOUtils.copy(inputStream, outputStream);
            //关闭流
            inputStream.close();
            outputStream.close();
        } catch (Exception e) {
            log.error("课程静态化异常:{}", e.toString());
            XueChengPlusException.cast("课程静态化异常");
        }

        return htmlFile;
    }

    /**
     * 上传静态化页面到minio
     *
     * @param courseId
     * @param file     静态化文件
     */
    @Override
    public void uploadCourseHtml(Long courseId, File file) {
        MultipartFile multipartFile = MultipartSupportConfig.getMultipartFile(file);
        String course = mediaServiceClient.uploadFile(multipartFile, "course/" + courseId + ".html");

        //清除临时文件
        file.delete();

        if (course == null) {
            XueChengPlusException.cast("上传静态文件异常");
        }
    }

    /**
     * 根据id获取课程发布信息
     *
     * @param courseId
     * @return
     */
    @Override
    public CoursePublish getCoursePublish(Long courseId) {
        CoursePublish coursePublish = coursePublishMapper.selectById(courseId);
        return coursePublish;
    }

    /**
     * 查询课程信息在缓存
     *
     * @param courseId
     * @return
     */
    @Override
    public CoursePublish getCoursePublishCatch(Long courseId) {
        //查询缓存
        String jsonString = stringRedisTemplate.opsForValue().get("course:" + courseId);
        if (jsonString != null) {
            System.out.println("=================从缓存查=================");
            CoursePublish coursePublish = JSON.parseObject(jsonString, CoursePublish.class);
            return coursePublish;
        } else {
            System.out.println("从数据库查询...");
            //从数据库查询
            CoursePublish coursePublish = getCoursePublish(courseId);
            if (coursePublish != null) {
                stringRedisTemplate.opsForValue().set("course:" + courseId, JSON.toJSONString(coursePublish));
            }
            return coursePublish;
        }
    }


    /**
     * @param courseId 课程id
     * @return void
     * @description 保存课程发布信息
     * @author Mr.M
     * @date 2022/9/20 16:32
     */
    private void saveCoursePublish(Long courseId) {
        //整合课程发布信息
        //查询课程预发布表
        CoursePublishPre coursePublishPre = coursePublishPreMapper.selectById(courseId);
        if (coursePublishPre == null) {
            XueChengPlusException.cast("课程预发布数据为空");
        }

        CoursePublish coursePublish = new CoursePublish();

        //拷贝到课程发布对象
        BeanUtils.copyProperties(coursePublishPre, coursePublish);
        coursePublish.setStatus("203002");
        CoursePublish coursePublishUpdate = coursePublishMapper.selectById(courseId);
        if (coursePublishUpdate == null) {
            coursePublishMapper.insert(coursePublish);
        } else {
            coursePublishMapper.updateById(coursePublish);
        }
        //更新课程基本表的发布状态
        CourseBase courseBase = courseBaseMapper.selectById(courseId);
        courseBase.setStatus("203002");
        courseBaseMapper.updateById(courseBase);

    }

    /**
     * @param courseId 课程id
     * @return void
     * @description 保存消息表记录，稍后实现
     * @author Mr.M
     * @date 2022/9/20 16:32
     */
    private void saveCoursePublishMessage(Long courseId) {
        MqMessage mqMessage = mqMessageService.addMessage("course_publish", String.valueOf(courseId), null, null);
        if (mqMessage == null) {
            log.error("保存消息表信息失败,参数为{}", courseId);
            XueChengPlusException.cast(CommonError.UNKOWN_ERROR);
        }

    }
}
